﻿using IPCMessage;
using KInterfaces;
using KXmlUIControl;
using LogLib;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip;

namespace KWindow.KPageCore
{
    public class PageProcessBase<T> : IPageProcess where T : class
    {
        /// <summary>
        /// 获取该类的单例实例。
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
        public static T Instance => SingletonFactory.Instance;

        /// <summary>
        /// 创建单例实例的单例类工厂。
        /// </summary>
        private class SingletonFactory
        {
            #region Fields
            /// <summary>
            /// 定义弱引用实例。
            /// </summary>
            private static readonly Lazy<T> _instance = new Lazy<T>(() => GetInstance());
            #endregion

            #region Properties
            /// <summary>
            /// 获取实例。
            /// </summary>
            internal static T Instance
            {
                get
                {
                    return _instance.Value;
                }
            }
            #endregion

            #region Constructors
            /// <summary>
            /// 防止编译器生成默认构造函数。
            /// </summary>
            private SingletonFactory()
            {
            }

            /// <summary>
            /// 显式静态构造函数，告诉c#编译器不要将类型标记为BeforeFieldInit。
            /// </summary>
            [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
            static SingletonFactory()
            {
            }
            #endregion

            #region Methods

            /// <summary>
            /// 获取特定类型的实例。
            /// </summary>
            /// <returns>The <see cref="T"/></returns>
            [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId =
                    "System.Type.InvokeMember")]
            private static T GetInstance()
            {
                var theType = typeof(T);
                T inst;
                try
                {
                    inst = (T)theType.InvokeMember(theType.Name,
                            BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic,
                            null, null, null, CultureInfo.InvariantCulture);
                }
                catch (MissingMethodException ex)
                {
                    throw new TypeLoadException(
                            string.Format(CultureInfo.CurrentCulture,
                                    "The type '{0}' must have a private constructor to be used in the Singleton pattern.",
                                    theType.FullName), ex);
                }
                return inst;
            }
            #endregion
        }

        public List<PageControlBase> Pages { get; protected set; } = new List<PageControlBase>();

        protected PageConfigService _config = null;

        public KJob Job { get; set; }

        public ShareData SD
        {
            get;
            set;
        }


        /// <summary>
        /// 指示页面业务是否正在进行中
        /// </summary>
        public bool IsRunning { protected set; get; } = false;

        public string ID { get; set; }

        public string ChineseName { get; set; }

        public string PageName { get; set; }

        /// <summary>
        /// 签名页面专用，表示是否已经完成签名，用于副屏进行墨迹采集的时候，主屏用这个属性判断签名的状态
        /// </summary>
        //public bool IsSignatureCompleted { get; set; } = false;

        public System.Windows.Forms.UserControl UIControl
        {
            get
            {
                if (Pages.Count > 0)
                {
                    return Pages[0];
                }
                return null;
            }
        }

        public PageControlBase MainPage
        {
            get
            {
                if (Pages.Count > 0)
                {
                    return Pages[0];
                }
                else
                {
                    return null;
                }
            }
        }

        public PageProcessBase()
        {
            _config = PageConfigService.Instance;
        }

        public string GetAssemblyDirectory()
        {
            Assembly ass = this.GetType().Assembly;
            string directory = Path.GetDirectoryName(ass.CodeBase);
            if (directory.StartsWith("file:\\"))
            {
                directory = directory.Substring(6);
            }
            return directory;
        }

        public void AddPage(PageControlBase page)
        {
            if (!Pages.Exists(r => r.HandleId == page.HandleId))
            {
                Pages.Add(page);
            }
        }

        // 初始化窗体控件
        public virtual void InitCtrl(int index)
        {
            try
            {
                if (index < Pages.Count)
                {
                    PageControlBase page = Pages[index];
                    page.InitCtrls();
                }
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
            }
        }

        // 业务初始化
        public virtual void Init()
        {

        }

        // 关闭, 退出业务流程
        public virtual void Exit()
        {
            for (int i = 0; i < Pages.Count; i++)
            {
                PageControlBase page = Pages[i];
                page.Close();
            }
        }

        //初始化数据
        public virtual void InitData()
        {
            IsRunning = false;
            try
            {
                Log.WriteAsync("Welcome to " + MainPage.Name);
            }
            catch (Exception ex)
            {
                Log.WriteAsync(ex.ToString());
            }
            for (int i = 0; i < Pages.Count; i++)
            {
                PageControlBase page = Pages[i];
                page.InitData();
            }
        }

        //初始化数据
        public virtual void UpdateData()
        {
            for (int i = 0; i < Pages.Count; i++)
            {
                PageControlBase page = Pages[i];
                page.UpdateData();
            }
        }

        public virtual void StartWork()
        {
            IsRunning = true;
            for (int i = 0; i < Pages.Count; i++)
            {
                PageControlBase page = Pages[i];
                page.StartWork();
                if (page.CountdownEnabled)
                {
                    page.StartCountdown();
                }
            }
        }

        public virtual void StopWork()
        {
            IsRunning = false;
            for (int i = 0; i < Pages.Count; i++)
            {
                PageControlBase page = Pages[i];
                page.StopWork();
            }
        }

        //清理数据
        public virtual void ClearData()
        {
            for (int i = 0; i < Pages.Count; i++)
            {
                PageControlBase page = Pages[i];
                page.ClearData();
            }
        }

        public void ApplyLanguage(string code)
        {
            for (int i = 0; i < Pages.Count; i++)
            {
                PageControlBase page = Pages[i];
                page.ApplyLanguage(code);
            }
        }

        #region EventHandler fields

        public event PageChangeEventHandler PageChanged;
        public event PageSwitchEventHandler PageSwitched;
        public event ModuleChangeEventHandler ModuleChanged;
        public event ModuleSwitchEventHandler ModuleSwitched;
        public event ClientRequestSentEventHandler RequestMsgSent;
        public event PageTipsUpdatedEventHandler PageTipsUpdated;

        public void RemoveEvents()
        {
            PageChanged = null;
            PageSwitched = null;
            ModuleChanged = null;
            ModuleSwitched = null;
            TakeAdminAction = null;
            LanguageChanged = null;
            RequestMsgSent = null;
            PageTipsUpdated = null;
        }

        public void GotoPage(PageTo dir)
        {
            if (PageChanged != null)
            {
                PageChanged(this, new PageChangedEventArgs(dir));
            }
        }

        public void GotoAnyPage(string pageName)
        {
            if (PageSwitched != null)
            {
                PageSwitched(this, new PageSwitchedEventArgs(pageName));
            }
        }

        public void GotoModuleApp(ModuleAppTo dir)
        {
            if (ModuleChanged != null)
            {
                ModuleChanged(this, new ModuleChangedEventArgs(dir));
            }
        }

        public void GotoAnyModuleApp(string appName)
        {
            if (ModuleSwitched != null)
            {
                ModuleSwitched(this, new ModuleSwitchedEventArgs(appName));
            }
        }

        public void Request(IPCRequestMessage msg)
        {
            if (RequestMsgSent != null)
            {
                RequestMsgSent(this, new ClientRequestSentEventArgs(msg));
            }
        }

        public void SetTip(string msg, float fontSize)
        {
            if (PageTipsUpdated != null)
            {
                PageTipsUpdated(this, new PageTipsUpdatedEventArgs(msg, fontSize));
            }
        }

        public virtual void ToNext()
        {
            string pageName = MainPage.Name;
            Log.WriteAsync($"{pageName} call ToNext");
            GotoPage(PageTo.Next);
        }

        public virtual void ToLast()
        {
            string pageName = MainPage.Name;
            Log.WriteAsync($"{pageName} call ToLast");
            GotoPage(PageTo.Last);
        }

        public virtual void ToHome()
        {
            string pageName = MainPage.Name;
            Log.WriteAsync($"{pageName} call ToHome");
            SD.ClearValue();
            GotoPage(PageTo.Home);
        }

        public virtual void ToEnd()
        {
            string pageName = MainPage.Name;
            Log.WriteAsync($"{pageName} call ToHome");
            GotoPage(PageTo.End);
        }

        public virtual void ToAny(string pageName)
        {
            string thePage = MainPage.Name;
            Log.WriteAsync($"{thePage} call ToAny: {pageName}");
            GotoAnyPage(pageName);
        }

        public virtual void ToHomeApp()
        {
            string thePage = MainPage.Name;
            Log.WriteAsync($"{thePage} call ToHomeApp.");
            GotoModuleApp(ModuleAppTo.Home);
        }

        public virtual void ToDefaultApp()
        {
            string thePage = MainPage.Name;
            Log.WriteAsync($"{thePage} call ToDefaultApp.");
            GotoModuleApp(ModuleAppTo.Default);
        }

        public virtual void ToAnyApp(string appName)
        {
            string thePage = MainPage.Name;
            Log.WriteAsync($"{thePage} call ToAnyApp: {appName}");
            GotoAnyModuleApp(appName);
        }

        public event TakeAdministratorActionEventHandler TakeAdminAction;
        public void OnTakeAdminAction(AdministratorAction action)
        {
            if (TakeAdminAction != null)
            {
                TakeAdminAction(this, new AdministratorActionTakenEventArgs(action));
            }
        }

        public event DelegateAppLanguageChanged LanguageChanged;
        public void OnLanguageChanged(string code)
        {
            if (LanguageChanged != null)
            {
                LanguageChanged(code);
            }
        }

        #endregion

        #region SharedData operation
        public T1 GetValue<T1>(string ValueId, object NullReturn = null)
        {
            return SD.GetValue<T1>(ValueId, NullReturn);
        }

        public bool ContainsKey(string key)
        {
            return SD.ContainsKey(key);
        }

        public void RemoveKey(string key)
        {
            SD.Remove(key);
        }

        public void SetValue(string ValueId, object NewValue, bool NotExistThenAdd = true)
        {
            SD.SetValue(ValueId, NewValue, NotExistThenAdd);
        }
        #endregion

        public virtual void PlayWelcomeVoice()
        {
            for (int i = 0; i < Pages.Count; i++)
            {
                var page = Pages[i];
                page.PlayWelcomeVoice();
            }
        }

        public virtual void AbortWork()
        {
            IsRunning = false;
            for (int i = 0; i < Pages.Count; i++)
            {
                var page = Pages[i];
                if (page.CountdownEnabled)
                {
                    page.StopCountdown();
                    page.AbortWork();
                }
            }
            ClearData();
            ToHome();
        }

    }
}
